import 'dart:typed_data';

import 'package:blog/src/generated/response/article_detail_data.pb.dart';
import 'package:blog/src/generated/response/home_data.pb.dart';
import 'package:dio/dio.dart';
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;

import '../src/generated/response/article_search_data.pb.dart';
import '../src/generated/models/article.pb.dart';
import '../src/generated/response/common_response.pb.dart' as $pb_common;
import '../src/generated/models/page.pb.dart';
import '../src/generated/models/setting.pb.dart';
import '../src/generated/models/category.pb.dart';
import 'api.dart';
import 'api_handle.dart';

class DioApiImpl implements Api {
  Dio _dio;
  ApiHandle _handle;

  DioApiImpl(this._dio, this._handle);

  Future<T?> protobufGet<T extends $pb.GeneratedMessage>(String api, T message,
      [Map<String, dynamic>? params, bool Function($pb_common
          .Response resp)? error]) async {
    try {
      final response = await _dio.request(api,
          queryParameters: params,
          options: Options(responseType: ResponseType.bytes));
      // 获取到的数据，通过指定的message 解析
      Uint8List bytes = response.data ?? [];
      var resp = $pb_common.Response.create();
      resp.mergeFromBuffer(bytes);

      if (resp.code != $pb_common.CodeEnum.SUCCESS ||
          !resp.data.canUnpackInto(message)) {
        print("url:$api,fail response:${resp.code}, msg:${resp.msg}");
        processError(resp, error);
        return null;
      }
      resp.data.unpackInto(message);
      return message;
    } catch (ex) {
      print("url:${api},exception:${ex.toString()}");
      return null;
    }
  }

  processError($pb_common.Response resp,
      bool Function($pb_common.Response resp)? error) {
    if (error != null) {
      error(resp);
    } else {
      _handle.toast(resp.msg);
    }
  }

  @override
  Future<ArticleDetail?> getArticleDetail(int id) async {
    var data = await protobufGet(
        "/api/blog/detail", ArticleDetailData.create(), {
      "article_id": id,
    });
    return data?.detail;
  }

  @override
  Future<SiteSetting?> getSiteSetting() async {
    return await protobufGet("/api/setting", SiteSetting.create());
  }

  @override
  Future<List<CategoryItem>> getCategoryItem(String? position) async {
    var categories = ["flutter", "MySQL", "Dart", "Go", "Rust"];
    return List.generate(
        categories.length,
            (index) =>
            CategoryItem(
                cateId: $fixnum.Int64(1),
                name: categories[index],
                description: categories[index],
                image: ''));
  }

  @override
  Future<List<ArticleItem>> getArticleItem(
      {int? page, int? pageSize, Map<String, dynamic> filter = const {}}) async {
    Map<String, dynamic> param = {
      ...{
        "page": page.toString(),
        "pageSize": pageSize.toString(),
      },
      ...filter,
    };
    var data = await protobufGet(
        "/api/blog/search", ArticleSearchData.create(), param);

    print("/api/blog/search length:${data?.articles.length} ${data?.articles.isNotEmpty}");
    return data?.articles ?? [];
  }

  @override
  Future<PageDetail?> getSinglePage(String pageName) async {
    return PageDetail(title: "", content: "");
  }

  @override
  Future<HomeData?> getHomePage() async {
    var data = await protobufGet("/api/page/home", HomeData.create());
    return data;
  }
}
